#ifndef __DALELIB_M3_H__
#define __DALELIB_M3_H__

#include <math.h>
#include <dalelib/maths/v2.h>
#include <dalelib/maths/v3.h>

namespace dalelib
{

class v2;
class v3;

class m3
{
private:

	float f[9];

public:

	m3(){}
	m3( const float* _Ptr );
	m3( const float _Value00, const float _Value01, const float _Value02, const float _Value03, const float _Value04, const float _Value05, const float _Value06, const float _Value07, const float _Value08 );
    m3( const v3 _Diagonal );
	m3( const v3 _Value0, const v3 _Value1, const v3 _Value2 );
//	const m3 operator =(const m3& _Value);

	static m3 const zero;
	static m3 const identity;

	static m3 translation(const v2& _Vec) { return m3( 1,0,0, 0,1,0, _Vec[0],_Vec[1],1); }
	static m3 scaling(const v2 _Scl) { return m3(_Scl[0],0,0, 0,_Scl[1],0, 0,0,1); }
	static m3 rotation(const float _Ang) { float sa = sinf(_Ang), ca = cosf(_Ang); return m3( ca, sa, 0, -sa, ca, 0, 0, 0, 1 ); }
	static m3 makeCross(const v3& _Value)
	{
//		return m3( 0,_Value[2],-_Value[1], -_Value[2],0,_Value[0], _Value[1],-_Value[0],0 );
		return m3( 0,_Value.z(),-_Value[1], -_Value[2],0,_Value[0], _Value[1],-_Value[0],0 );
	}
	static m3 outer(const v3& _Value1,const v3& _Value2)
	{
		return m3(
			_Value1[0]*_Value2[0], _Value1[1]*_Value2[0], _Value1[2]*_Value2[0],
			_Value1[0]*_Value2[1], _Value1[1]*_Value2[1], _Value1[2]*_Value2[1],
			_Value1[0]*_Value2[2], _Value1[1]*_Value2[2], _Value1[2]*_Value2[2] );
	}
	static m3 skewSymmetric(const v3& _Value)
	{
		return m3(0,-_Value[2],_Value[1],_Value[2],0,-_Value[0],-_Value[1],_Value[0],0);

	}

	const float& operator[](const int _Index) const { return f[_Index]; }
	      float& operator[](const int _Index)       { return f[_Index]; }

	const float* ptr() const { return f; }
	      float* ptr()       { return f; }
	v3 x();
	v3 y();
	v3 z();
	v2 getTranslationPart();

	m3 operator-() const;

	m3 transpose() const;
	m3 fastInverse() const;
	m3 inverse() const;
	m3 noRotation() const;
	m3 noTranslation() const;

	static m3 rotationX(const float _Angle)
	{
		const float sa = sinf(_Angle), ca = cosf(_Angle);
		return m3( 1,0,0,  0,ca,-sa,  0,sa,ca );
	}
	static m3 rotationY(const float _Angle)
	{
		const float sa = sinf(_Angle), ca = cosf(_Angle);
		return m3( ca,0,-sa,  0,1,0,  sa,0,ca );
	}
	static m3 rotationZ(const float _Angle)
	{
		const float sa = sinf(_Angle), ca = cosf(_Angle);
		return m3( ca,-sa,0,  sa,ca,0,  0,0,1 );
	}


	m3 operator*( const float _Value ) const;
	m3 operator/( const float _Value ) const;
	v3 operator*( const v3& _Value ) const;
	m3 operator*( const m3& _Value ) const;
	m3 operator+( const m3& _Value ) const;
	m3 operator-( const m3& _Value ) const;
	void operator+=(const m3& _Value);
	void lookAt(const v2& _Pos,const v2& _Tgt);

	void print(const std::string _Str="") const;

};

} // namespace dalelib

#endif
